# -*- coding: utf-8 -*-

import os, subprocess, thread, mox
from datetime import time

from paste.httpserver import serve
from paste.deploy.loadwsgi import appconfig

from sqlalchemy import create_engine
from sqlalchemy.orm import contains_eager

from hurryoff.web.run import app
from hurryoff.db.base import Base
from hurryoff.db import *
import hurryoff.spiders.trains.uz as uz

class SpiderTests(mox.MoxTestBase):

    GlobalTrainNumberPattern = ".*(<select.*?name=\"T1\".*>.*<option.*</select>).*"
    TrainDetailsPattern = ".*(<h1>Інформація по номеру поїзда</h1>(.*?</table>){6}).*"

    @classmethod
    def setUpClass(cls):
        if (os.path.dirname(__file__) not in ('', None)):
            os.chdir(os.path.dirname(__file__))
        cls.serverThread = thread.start_new_thread(cls.startServer, ())
        cls.setupDB()

    @classmethod
    def tearDownClass(cls):
        subprocess.Popen(["kill", "-9", str(cls.serverPid)], stdout=subprocess.PIPE)

    def test_parseTrain_OneInGlobal(self):
        trainNumber = 1

        self.mox.StubOutWithMock(uz, "readData")
        globalRawData = open('rawData/trainGlobal_%d.htm' % trainNumber, 'r').read()
        trainDetails = open('rawData/train_%d.htm' % trainNumber, 'r').read()

        stops = [
            Stop(Station(u"москва київська", countryCode="RU"), 0, departure=time(23, 23)),
            Stop(Station(u"сухиничі-головні", countryCode="RU"), 1, arrival=time(2, 3), departure=time(2, 21)),
            Stop(Station(u"суземка", countryCode="RU"), 2, arrival=time(4, 27), departure=time(4, 57)),
            Stop(Station(u"хутір михайлівський", countryCode="UA"), 3, arrival=time(4, 18), departure=time(4, 38)),
            Stop(Station(u"київ-пас.", countryCode="UA"), 4, arrival=time(8, 0))
        ]
        expected = Train(number='1', name=u'"столичный экспресс"', stops=stops)

        uz.readData(mox.IgnoreArg(), pattern=mox.IsA(self.GlobalTrainNumberPattern)) \
            .AndReturn(globalRawData)
        uz.readData(mox.IgnoreArg(), chunk_size=mox.IgnoreArg(), pattern=mox.IsA(self.TrainDetailsPattern)) \
            .AndReturn(trainDetails)

        self.mox.ReplayAll()

        spider = uz.UzTrainsSpider(echo=True)
        spider.processTrain(trainNumber)

        session = getSession()
        with session.begin(subtransactions=True):
            train = session.query(Train) \
                .join(Train.stops) \
                .options(contains_eager(Train.stops)) \
                .filter(Train.number == trainNumber) \
                .one()

            self.assertEquals(train.rawData.data, unicode(trainDetails, encoding="utf-8"))
            self.assertEquals(train, expected)

    def test_parseTrain_ManyInGlobal(self):
        subTrainNumbers = (u'3М', '3')
        rawData = {}

        train3M_stops = [
            Stop(Station(u"москва київська", countryCode="RU"), 0, departure=time(21, 29)),
            Stop(Station(u"калуга-2", countryCode="RU"), 1, arrival=time(0, 5), departure=time(0, 10)),
            Stop(Station(u"сухиничі-головні", countryCode="RU"), 2, arrival=time(1, 13), departure=time(1, 36)),
            Stop(Station(u"брянськ-орловськ", countryCode="RU"), 3, arrival=time(3, 28), departure=time(3, 57)),
            Stop(Station(u"брянськ-льговский", countryCode="RU"), 4, arrival=time(4, 8), departure=time(4, 10)),
            Stop(Station(u"суземка", countryCode="RU"), 5, arrival=time(5, 26), departure=time(5, 56)),
            Stop(Station(u"хутір михайлівський", countryCode="UA"), 6, arrival=time(5, 25), departure=time(5, 55)),
            Stop(Station(u"терещенська", countryCode="UA"), 7, arrival=time(6, 25), departure=time(6, 27)),
            Stop(Station(u"конотоп-пас.", countryCode="UA"), 8, arrival=time(7, 15), departure=time(7, 17)),
            Stop(Station(u"київ-пас.", countryCode="UA"), 9, arrival=time(9, 48))
        ]
        train3_stops = [
            Stop(Station(u"москва київська", countryCode="RU"), 0, departure=time(21, 29)),
            Stop(Station(u"калуга-2", countryCode="RU"), 1, arrival=time(0, 5), departure=time(0, 10)),
            Stop(Station(u"сухиничі-головні", countryCode="RU"), 2, arrival=time(1, 13), departure=time(1, 36)),
            Stop(Station(u"брянськ-орловськ", countryCode="RU"), 3, arrival=time(3, 28), departure=time(3, 57)),
            Stop(Station(u"брянськ-льговский", countryCode="RU"), 4, arrival=time(4, 8), departure=time(4, 10)),
            Stop(Station(u"суземка", countryCode="RU"), 5, arrival=time(5, 26), departure=time(5, 56)),
            Stop(Station(u"хутір михайлівський", countryCode="UA"), 6, arrival=time(5, 25), departure=time(5, 55)),
            Stop(Station(u"терещенська", countryCode="UA"), 7, arrival=time(6, 25), departure=time(6, 27)),
            Stop(Station(u"наславча", countryCode="MD"), 8, arrival=time(0, 4), departure=time(0, 10)),
            Stop(Station(u"окниця", countryCode="MD"), 9, arrival=time(0, 35), departure=time(1, 5)),
            Stop(Station(u"дондюшани", countryCode="MD"), 10, arrival=time(1, 35), departure=time(1, 45)),
            Stop(Station(u"софія", countryCode="MD"), 11, arrival=time(2, 25), departure=time(2, 35)),
            Stop(Station(u"червен бряг", countryCode="BG"), 12, arrival=time(3, 38), departure=time(3, 39)),
            Stop(Station(u"мездра", countryCode="BG"), 13, arrival=time(4, 13), departure=time(4, 14)),
            Stop(Station(u"софія", countryCode="BG"), 14, arrival=time(5, 55))
        ]
        expectedTrains  = {u'3М' : Train(number=u'3М', name=u'"київ"', stops=train3M_stops),
                            '3'  : Train(number='3', name=u'безпересадочний вагон "болгария экспресс"', stops=train3_stops)}

        self.mox.StubOutWithMock(uz, "readData")
        globalRawData = open('rawData/trainGlobal_%d.htm' % 3, 'r').read()

        uz.readData(mox.IgnoreArg(), pattern=mox.IsA(self.GlobalTrainNumberPattern)) \
            .AndReturn(globalRawData)

        for subTrain in subTrainNumbers:
            rawData[subTrain] = open('rawData/train_%s.htm' % subTrain, 'r').read()
            uz.readData(mox.IgnoreArg(), chunk_size=mox.IgnoreArg(), pattern=mox.IsA(self.TrainDetailsPattern)) \
                .AndReturn(rawData[subTrain])

        self.mox.ReplayAll()

        spider = uz.UzTrainsSpider(echo=True)
        spider.processTrain(3)

        session = getSession()

        for subTrain in subTrainNumbers:
            with session.begin(subtransactions=True):
                train = session.query(Train) \
                    .join(Train.stops) \
                    .options(contains_eager(Train.stops)) \
                    .filter(Train.number == subTrain) \
                    .one()

                self.assertEquals(train.rawData.data, unicode(rawData[subTrain], encoding="utf-8"))
                self.assertEquals(train, expectedTrains[subTrain])

    @classmethod
    def startServer(cls):
        cls.serverPid = os.getpid()
        config = appconfig("config:test_web.ini#alchemy", relative_to='.')
        serve(app(None, **config), port=6543)

    @classmethod
    def setupDB(cls):
        engine = create_engine("mysql://test:testpswd@localhost/test_hurryoff?charset=utf8", echo=True)
        DBSession.configure(bind=engine)
        Base.metadata.bind = engine
        Base.metadata.drop_all(Base.metadata.bind)
        Base.metadata.create_all(Base.metadata.bind)

